#ifndef _SERVER_MANAGER_H_
#define _SERVER_MANAGER_H_

#include "ServiceEx.h"
#include "SessionBase.h"
#include "RpcSessionBase.h"
#include "PacketParserEx.h"
#include "SessionManager.h"
#include "ConnSession.h"
#include "Timer.h"
#include "Header.h"
#include "LogEx.h"
#include "global.h"

union TimerData
{
    struct ReconnectTimerData
    {
        u32 ip;
        s32 port;
        void *data;
    } _reConnData;

    struct RegisterGateData
    {
        void *session;
        void *gtmgr;
    } _regGateData;

    void *data;
    u64 param;
};

class CServerManager
{
    SINGLETON_CLASS_DEFINE(CServerManager);

public:
    enum
    {
        Timer_Count = 1000,
        CheckSessionAlive_Timer = 20000,
    };

    bool Init(u64 sid, bool delayConnect, bool checkAlive, u64 idfrom=1);
    template<typename TSession, typename TRpcSession, typename TPacketParser, s32 TimerCount, s32 CurlCount>
    bool Start()
    {
        if( m_service )
        {
            LOG_ERROR( "[%s][%s][%d] aleardy start", __FILE__, __FUNCTION__, __LINE__ );
            return false;
        }
        SELF_ASSERT(m_config, return false;);
        bool ret = StartServiceEx<TSession, TRpcSession, TPacketParser, TimerCount, CurlCount>(
                    m_config->_cs._Port, 
                    m_config->_cs._ConnCount,
                    m_config->_cs._SendSize,
                    m_config->_cs._RecvSize,
                    m_config->_cs._RpcConnCount,
                    m_config->_cs._RpcSendSize,
                    m_config->_cs._RpcRecvSize,
                    m_config->_cs._IoCount,
                    m_config->_cs._EventQueueSize );
        if( !ret )
        {
            LOG_ERROR( "[%s][%s][%d] StartServiceEx failed", __FILE__, __FUNCTION__, __LINE__ );
            return false;
        }

        m_service = CServiceExManager::Instance().GetServiceEx();
        _InitRpcServers();
        if( m_checkAlive )
        {
            _StartCheckSessionAlive();
        }
        LOG_INFO( "[%s][%s][%d] Server[%llu][%s:%d] Start.", __FILE__, __FUNCTION__, __LINE__,
                m_sid, m_config->_cs._Ip.c_str(), m_config->_cs._Port );
        return true;
    }
    void Stop();

    u64 GetId();
    SGLib::IPacketParser* GetPacketParser();
    ServerConfig* GetServerConfig(){ return m_config; }
    CGlobalConfig* GetGlobalConfig(){ return  m_global; }
    void ReloadServerConfig();
    bool NeedCheckAlive() { return m_checkAlive; }

    void CloseSession(u64 sessionid);

    void SendMsgToServer(u64 serverid, u32 msgid, const IMessage &msg);
    void SendMsgToServers(std::vector<u64> &servers, u32 msgid, const IMessage &msg);
    void BroadcastToServers(u32 msgid, const IMessage &msg);
    
    void SendMsgToRpcServer(u64 serverid, u32 msgid, const IMessage &msg);
    void SendMsgToRpcServers(std::vector<u64> &servers, u32 msgid, const IMessage &msg);
    void BroadcastToRpcServers(u32 msgid, const IMessage &msg);
	void SendMsgToRpcServerWithHead(u64 serverid, u32 msgid, const IMessage &msg, char *head, int len);

    void SendMsgToSession(u64 sessionid, const char *msg, s32 len);
    void SendMsgToSession(u64 sessionid, u32 msgid, const IMessage &msg);
    void SendMsgToSessions(std::vector<u64> &sessionids, u32 msgid, const IMessage &msg);
    void BroadcastToSessions(u32 msgid, const IMessage &msg);

    s32 AddTimer(u32 elapse, SGLib::CallBackFunc callback, void *data, s32 len, bool persist=false );
    void DelTimer(s32 timerid);

    // send msg to clients by gate
    void SendMsg2Client(u64 gateid, u64 sessionid, u32 msgid, const IMessage &msg);
    void SendMsg2Clients(u64 gateid, std::vector<u64> &sessionids, u32 msgid, const IMessage &msg);

#ifdef _USE_CURL_
    void PostRequest(const std::string &url, const std::string &postdata, postRspCallback rspfunc, void *data, s32 len, s32 timeOut=5);
#endif
    void SignalMask();
    
private:
    static void CheckSessionAliveTimerCallBack(void *data, s32 len);
    bool _InitGlobalConfig(u64 sid, CGlobalConfig **global, ServerConfig **config);
    void _DoCheckSessionAlive();
    void _StartCheckSessionAlive();
    void _InitRpcServers();
    void _SigHandle();

private:
    u64 m_sid; // serverid
    bool m_delayConnect;
    bool m_checkAlive;
    CGlobalConfig *m_global;
    ServerConfig *m_config;
    IServiceEx *m_service;
};

#endif

